var XMPP_HOST = 'zy48';
var BOSH_SERVICE = 'http://48.lsu.pw:7070/http-bind/';
var connection = null;

var peerjs;
var webrtcSupport = false;

/**
 * prefix name like 'test'
 */
var myName;

/**
 * pure jid like 'test@49.lsu.pw'
 */
var myJid;
var myPasswd;

var siteCode;

var logLevel = 0;

var xmppPres = {};
xmppPres.online = 'online';
xmppPres.offline = 'offline';
xmppPres.waiting = 'waiting';
xmppPres.chating = 'chating';
xmppPres.afterChat = 'after';

/**
 * Generate unique id like ->
 *   "bfc7d682_c7f2e1ed_ab0c0193_63b53085"
 *
 * @Source http://stackoverflow.com/questions/105034/create-guid-uuid-in-javascript?page=1&tab=votes#answer-105074
 * @return string id.
 */
function guid() {
  function s4() {
    return Math.floor((1 + Math.random()) * 0x10000)
        .toString(16)
        .substring(1);
  }

  return s4() + s4() + '_' + s4() + s4() + '_' + s4() + s4() + '_' + s4() + s4();
};


function preventDefault(evt){
  evt.preventDefault();
  evt.stopPropagation();
}

function checkWebrtcSupport() {
  if(navigator.userAgent.search('Chrome') >= 0) {
    webrtcSupport = true;
  } else {
    webrtcSupport = false;
  }
}

/************************************************************************************************************
 * 
 * file functions.
 *
 ***********************************************************************************************************/


var tmpDataUrl;
var fileDataUrlReader = new FileReader();
fileDataUrlReader.onload = function (fileReaderEvent) {
  tmpDataUrl = fileReaderEvent.target.result;
};

function setBlobToImgType(blob) {
  blob = new Blob([blob],{type : 'image/jpeg'})
  return blob;
}

function getDataUrlOfFile(file) {
  fileDataUrlReader.readAsDataURL(file);
  return tmpDataUrl;
}

function queryClips() {
  for(name in localStorage) {
    var value = localStorage[name];
    if(name.search('clip-') == 0) {
      addClip(value);
    }
  }
}

function saveClip(clipText) {
  localStorage.setItem('clip-' + clipText, clipText);
}

/***********************************************************************************************************************
 *
 * log functions.
 *
 **********************************************************************************************************************/

function consoleLog(mess, level) {
  if (logLevel >= level) {
    console.log(mess);
  }
}

/***********************************************************************************************************************
 *
 * DOM functions.
 *
 **********************************************************************************************************************/

function hideLoginLayer() {
  $('.login-layer-container').hide();
}

function showLoginLayer() {
  $('.login-layer-container').show();
}

function updateCustomItem(fullName, status) {
  if(!status) {
    status = xmppPres.online;
  }
  var li = document.createElement('li');
  var domId = fullName + '-custom-info';
  if ($('#' + domId).length == 0) {
    $(li).attr('class', 'custom-item');
    $(li).attr('id', fullName + '-custom-info');
    $(li).html('<a class="custom-name" href="javascript:;" title="' + fullName + '">'
        + fullName.substr(0, 8)
        + '</a>'
        + '<span class="custom-status ' + status + '"></span>');
    $('.custom-list').append(li);
  }
  li = $('#' + domId);
  $(li).children('.custom-status').attr('class', 'custom-status ' + status);
}

function removeCustomItem(fullName) {
  $('#' + fullName + '-custom-info').remove();
}

function removeChatPanel(chatPanel) {
  $(chatPanel).remove();
}

function messageBoardScrollToBottom(messageBoard) {
  $(messageBoard).animate({scrollTop: 1000}, 100);
}


/**
 * Show message on chat board.
 *
 * @param source the sender of the message, 1 for peer, 2 for self. //
 */
function appendMessage(source, content, chatPanel) {
  var container = document.createElement('div');
  var mes = document.createElement('span');
  var timestamp = document.createElement('p');
  timestamp.innerHTML = Date();
  $(timestamp).addClass('timestamp');
  mes.innerHTML = content;
  $(container).append(mes);
  $(container).append(timestamp);
  if (source == 1) {
    $(container).addClass("message-in");
  } else if (source == 2) {
    $(container).addClass("message-out");
  }
  if (!chatPanel) {
    messageBoardScrollToBottom($(".chat-panel.active .message-board"));
    $('.chat-panel.active').children('.message-board').append(container);
  } else {
    var messageBoard = $(chatPanel).children('.message-board')
    messageBoardScrollToBottom($(messageBoard));
    $(messageBoard).append(container);
  }
}


/**
 * @param messageSource the sender of the message, 1 for peer, 2 for self. TODO: 3 for notify.
 */
function appendImageMessage(source, blobUrl, chatPanel) {
  var container = document.createElement('div');
  var mes = document.createElement('span');
  var timestamp = document.createElement('p');
  timestamp.innerHTML = Date();
  $(timestamp).addClass('timestamp');
  mes.innerHTML = '<img class="chat-image" src="' + blobUrl + '">';
  $(container).append(mes);
  $(container).append(timestamp);
  if (source == 1) {
    $(container).addClass("message-in");
  } else if (source == 2) {
    $(container).addClass("message-out");
  }
  if (!chatPanel) {
    messageBoardScrollToBottom($(".chat-panel.active .message-board"));
    $('.chat-panel.active').children('.message-board').append(container);
  } else {
    var messageBoard = $(chatPanel).children('.message-board')
    messageBoardScrollToBottom($(messageBoard));
    $(messageBoard).append(container);
  }
}


function addChatPanel(fullName) {
  var panelId = $('#' + fullName + '-custom-panel');
  if ($(panelId).length > 0) {
    return;
  }
  var chatPanel = document.createElement('div');
  $(chatPanel).addClass('chat-panel');
  $(chatPanel).attr('id', fullName + '-custom-panel');
  $(chatPanel).html('<div class="chating-titlebar">'
      + '<span>' + fullName.substr(0, 8) + '</span>'
      + '<a class="close-chat-panel" href="javascript:;">'
      + '<i class="iconfont">&#xe603;</i></a>'
      + '</div>'
      + '<div class="message-board">'
      + '</div>');
  $('.chat-panel-container').append(chatPanel);
}


function showImageViewerLayer() {
  $('.img-viewer-layer').show();
}

function hideImageViewerLayer() {
  $('.img-viewer-layer').hide();
}

function addClip(clipText) {
  var clipContainer = document.createElement('div');
  $(clipContainer).addClass('clip-container');
  $(clipContainer).html('<a href="javascript:;" class="clip-button">'
                      + clipText + '</a>'
                      + '<a class="clip-delete-button">x</a>');
  $('.clipboard-container').prepend(clipContainer);
}


/***********************************************************************************************************************
 *
 * XMPP functions.
 *
 **********************************************************************************************************************/

function getBareJid(fullJid) {
  var idx = fullJid.search('/');
  if(idx >= 0) {
    fullJid = fullJid.substr(0, idx);
  }
  return fullJid;
}

function getFullName(jid) {
  var idx = jid.search('@');
  if(idx >= 0) {
    jid = jid.substr(0, idx);
  }
  return jid;
}


function askSubscribe(pureJid) {
  connection.send($pres({to: pureJid, type: 'subscribe'}).tree());
}

function subscribedTo(pureJid) {
  connection.send($pres({to: pureJid, type: 'subscribed'}).tree());
}


function register() {
  connection.register.connect(XMPP_HOST, onConnect);
}

function onMessage(msg) {
  var from = msg.getAttribute('from');
  from = getBareJid(from);
  var type = msg.getAttribute('type');
  consoleLog('on message from ' + from + ', type ' + type, 1);
  var peerName = getFullName(from);
  var panelId = peerName + '-custom-panel';
  if (from.search('-custom-') >= 0) {
    addChatPanel(peerName);
  }
  var body = msg.getElementsByTagName('body')[0];
  if (type == 'chat' && body) {
    appendMessage(1, Strophe.getText(body), $('#' + panelId));
  }
  return true;
}

function onSubscribe(subs) {
  var suber = subs.getAttribute('from');
  subscribedTo(suber);
}

function onRosterLeave(pres) {
  var roster = pres.getAttribute('from');
  var fullName = getFullName(roster);
  removeChatPanel($('#' + fullName + '-custom-panel'));
  removeCustomItem(fullName);
}



function onPresence(pres) {
  var presType = pres.getAttribute('type');
  if(presType == 'subscribe') {
    onSubscribe(pres);
    return true;
  }
  if(presType == 'unavailable') {
    onRosterLeave(pres);
    return true;
  }
  var from = pres.getAttribute('from');
  var status = pres.getElementsByTagName('status');
  status = Strophe.getText(status[0]);
  consoleLog('on pres from ' + from + ', status ' + status, 1);
  if (from.search('-custom-') >= 0) {
    var fullName = getFullName(from);
    updateCustomItem(fullName, status);
    return true;
  }
  return true;
}

function onConnect(status) {
  if (status == Strophe.Status.REGISTER) {
    connection.register.fields.username = myName;
    connection.register.fields.password = myPasswd;
    consoleLog('register with ' + myName + ', ' + myPasswd, 1);
    connection.register.submit();
  } else if (status == Strophe.Status.REGISTERED) {
    consoleLog("registered!", 1);
    connection.authenticate();
  } else if (status == Strophe.Status.CONFLICT) {
    consoleLog("Contact already existed!", 1);
  } else if (status == Strophe.Status.NOTACCEPTABLE) {
    consoleLog("Registration form not properly filled out.", 1)
  } else if (status == Strophe.Status.CONNECTING) {
    consoleLog("xmpp connecting", 1);
  } else if (status == Strophe.Status.CONNFAIL) {
    consoleLog("xmpp connect fail", 1);
  } else if (status == Strophe.Status.DISCONNECTING) {
    consoleLog("xmpp disconnecting", 1);
  } else if (status == Strophe.Status.DISCONNECTED) {
    consoleLog("xmpp disconnected", 1);
  } else if (status == Strophe.Status.CONNECTED) {
    consoleLog("xmpp connected", 1);
    connection.addHandler(onMessage, null, 'message', null, null, null);
    connection.addHandler(onPresence, null, 'presence', null, null, null);
    sendPresence(xmppPres.online);
    buildPeerjs();
  }
  return true;
}


function login(jid, passwd) {
  connection.connect(jid,
      passwd,
      onConnect);
};

/**
 * Announce presence.
 */
function sendPresence(pres) {
  connection.send($pres().c('status', {}, pres).tree());
}

/**
 * Send a text chat message to Someone.
 */
function sendChatMessage(receiverJid, textMessage) {
  connection.send($msg({to: receiverJid, from: myJid, type: 'chat'})
      .cnode(Strophe.xmlElement('body', textMessage))
      .tree());
};

function pickUp(prefixName) {
  var jid = prefixName + '@' + XMPP_HOST;
  connection.send(
    $msg({to: jid, type: 'hello'}).tree());
}

function disconnect() {
  connection.disconnect();
  peerjs.disconnect();
}



/*************************************************************************************************************
 *
 * peerjs functions.
 *
 ************************************************************************************************************/

var dataView;
var dataBlob;
var dataUrl;

function onPeerjsConnect(conn) {
  if (conn.label === 'img') {
    consoleLog('on img connect from ' + conn.peer, 1);
    conn.on('data', function(data) {
      consoleLog('on img in connect with ' + conn.peer, 1);
      if (data.constructor === ArrayBuffer) {
        dataView = new Uint8Array(data);
        dataBlob = new Blob([dataView]);
        dataBlob = setBlobToImgType(dataBlob);
        dataUrl = window.URL.createObjectURL(dataBlob);
        appendImageMessage(1, dataUrl, $('#' + conn.peer + '-custom-panel'))
      }
    });
  }
}

function peerJsConnectTo(peerId) {
  var f = peerjs.connect(peerId, { label: 'img', reliable: true });
  f.on('open', function() {
    onPeerjsConnect(f);
  });
  f.on('error', function(err) { consoleLog(err, 2); });
}

function buildPeerjs() {
  if(webrtcSupport) {
    peerjs = new Peer(myName, {
      // Set API key for cloud server (you don't need this if you're running your
      // own.
      key: 'x7fwx2kavpy6tj4i',

      // Set highest debug level (log everything!).
      debug: 3,

      // Set a logging function:
      logFunction: function() {
        var copy = Array.prototype.slice.call(arguments).join(' ');
        consoleLog(copy, 2);
      }
    });

    // Show this peer's ID.
    peerjs.on('open', function(id){
      consoleLog('peer on open, id: ' + id, 2);
    });

    peerjs.on('error', function(err) {
      consoleLog(err, 2);
    });

    peerjs.on('connection', onPeerjsConnect);
  }
}


$(document).ready(function () {

  siteCode = new RegExp(".{8}\$").exec(location.pathname)[0];
  connection = new Strophe.Connection(BOSH_SERVICE);
  /*connection.connect('test@49.lsu.pw', 'fortest', onConnect);
   peerJid = 'cc1@49.lsu.pw';*/
  if(logLevel >= 3) {
    $('#logbox').show();
    connection.rawInput = function (data) {
      $('#logbox').append('<div></div>').append(document.createTextNode('recv: ' + data));
    };
    connection.rawOutput = function (data) {
      $('#logbox').append('<div></div>').append(document.createTextNode('send: ' + data));
    };
  }

  queryClips();
  $('body').on('click', '.send-button', function () {
    var message = $('.text-input').val();
    if (message != '' && $('.chat-panel.active').length > 0 && connection.connected) {
      var peerName =  $('.chat-panel.active').attr('id');
      peerName = peerName.substr(0, peerName.search('-custom-panel'));
      var peerJid = peerName + '@' + XMPP_HOST;
      sendChatMessage(peerJid, message);
      appendMessage(2, message);
      $('.text-input').val('');
    }
  });

  $('body').on('change', '#img-input', function() {
    myImgFile = $(this)[0].files;
    myImgFile = myImgFile[0];
    if($('.chat-panel.active').length > 0) {
      var peerName = $('.chat-panel.active').attr('id');
      peerName = peerName.substr(0, peerName.search('-custom-panel'));
      var c = peerjs.connections[peerName][0];
      appendImageMessage(2, window.URL.createObjectURL(myImgFile), $('.chat-panel.active'));
      c.send(myImgFile);
    }
  });

  $('.img-button').on('click', function() {
    consoleLog('img-button clicked', 1);
    $('#img-input').click();
  });

  $('body').on('click', '.close-chat-panel', function () {
    removeChatPanel($(this).parents('.chat-panel'));
  });

  $('body').on('click', '.chat-panel', function () {
    $('.chat-panel.active').removeClass('active');
    $(this).addClass('active');
  });

  $('body').on('click', '.custom-name', function () {
    var prefixName = $(this).attr('title');
    if ($(this).siblings('.custom-status.' + xmppPres.chating).length > 0) {
      return;
    }
    addChatPanel(prefixName);
    pickUp(prefixName);
  });

  $('body').on('keypress', '.text-input', function (event) {
    if (event.keyCode == 13) {
      $('.send-button').click();
    }
  });

  $('body').on('keypress', '.userpasswd-input', function (event) {
    if (event.keyCode == 13) {
      $('#login-botton').click();
    }
  });

  $('body').on('click', '#login-botton', function() {
    myName = $('.username-input').val();
    myName = myName + '-service-' + siteCode;
    myJid = myName + '@' + XMPP_HOST;
    myPasswd = $('.userpasswd-input').val();
    if(myName && myPasswd) {
      login(myJid, myPasswd);
      hideLoginLayer();
    $('.username-input').val('');
    $('.userpasswd-input').val('');
    }
  });


  $('body').on('click', '.chat-image', function () {
    var imgUrl = $(this).attr('src');
    $('.img-show').attr('src', imgUrl);
    showImageViewerLayer();
  });


  $('body').on('click', '.img-viewer-close-button', function () {
    hideImageViewerLayer();
  });  

  $('body').on('click', '.clip-button', function () {
    var container = $(this).parents('.clip-container');
    var clip = $(this).html();
    var input = $('.text-input').val();
    $('.text-input').val(input + clip);
  });

  $('body').on('click', '.clip-delete-button', function () {
    var container = $(this).parents('.clip-container')[0]
    var clip = $(container).children('.clip-button')[0];
    clip = $(clip).html();
    localStorage.removeItem('clip-' + clip);
    $(container).remove();
  });

  $('body').on('click', '.add-clip-button', function () {
    if($('#add-clip-input').attr('status') == 'show') {
      var clip = $('#add-clip-input').val();
      if(clip == '') return;
      saveClip(clip);
      addClip(clip);
      $('#add-clip-input').attr('status', 'hide');
      $('#add-clip-input').hide();
      var clip = $('#add-clip-input').val('');
    } else {
      $('#add-clip-input').attr('status', 'show');
      $('#add-clip-input').show();
    }
  });


  checkWebrtcSupport();

  window.onunload = window.onbeforeunload = function(e) {
    disconnect();
    if (!!peer && !peer.destroyed) {
      peer.destroy();
    }
  };
  

});
